#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>

/*
 *  gcc pmsq1.c -o pmsq -lpthread && ./pmsq
 */
#define QUEUE_SIZE 10

typedef enum {
    PRIORITY_HIGH = 0,
    PRIORITY_MEDIUM = 1,
    PRIORITY_LOW = 2,
    PRIORITY_LEVELS
} Priority;

typedef struct {
    int data;
    Priority priority;
} Message;

typedef struct {
    Message buffer[QUEUE_SIZE];
    int head, tail, count;
} MsgQueue;

typedef struct {
    MsgQueue queues[PRIORITY_LEVELS];
    pthread_mutex_t mutex;
    pthread_cond_t not_empty;
    pthread_cond_t not_full;
} PriorityQueue;

PriorityQueue *pq;

// 初始化
void init_priority_queue() {
    printf("Initializing priority queue...\n");
    pq = (PriorityQueue *)malloc(sizeof(PriorityQueue));
    if (pq == NULL) {
        perror("Failed to allocate memory for priority queue");
        exit(EXIT_FAILURE);
    }

    for (int i = 0; i < PRIORITY_LEVELS; ++i) {
        pq->queues[i].head = pq->queues[i].tail = pq->queues[i].count = 0;
    }
    pthread_mutex_init(&pq->mutex, NULL);
    pthread_cond_init(&pq->not_empty, NULL);
    pthread_cond_init(&pq->not_full, NULL);

    printf("Priority queue initialized.\n");
}

// 入队（带优先级，阻塞）
void enqueue(int priority, void* msg) {
    pthread_mutex_lock(&pq->mutex);
    MsgQueue *q = &pq->queues[priority];

    while (q->count == QUEUE_SIZE) {
        pthread_cond_wait(&pq->not_full, &pq->mutex);
    }

    q->buffer[q->tail] = msg;
    q->tail = (q->tail + 1) % QUEUE_SIZE;
    q->count++;

    pthread_cond_signal(&pq->not_empty);
    pthread_mutex_unlock(&pq->mutex);
}

// 出队（按优先级，阻塞）
Message dequeue(int* priority) {
    pthread_mutex_lock(&pq->mutex);

    while (1) {
        for (int i = 0; i < PRIORITY_LEVELS; ++i) {
            MsgQueue *q = &pq->queues[i];
            if (q->count > 0) {
                Message msg = q->buffer[q->head];
                q->head = (q->head + 1) % QUEUE_SIZE;
                q->count--;
                pthread_cond_signal(&pq->not_full);
                pthread_mutex_unlock(&pq->mutex);

                *priority = i;  // 返回优先级
                return msg;
            }
        }
        // 所有队列都空，等待
        pthread_cond_wait(&pq->not_empty, &pq->mutex);
    }
}

#define COUNT 10

// 示例生产者
void *producer() {
    for (int i = 0; i < 100; i++) {
        Message msg;
        msg.data = i;
        msg.priority = rand() % PRIORITY_LEVELS;  // 随机优先级
        int priority = PRIORITY_HIGH;
        enqueue(priority, msg);
        printf("Produced: %d [Priority: %d]\n", msg.data, priority);
        usleep(100000);
    }
    return NULL;
}

// 示例消费者
void *consumer() {
    for (int i = 0; i < 10; i++) {
        int priority = 0;
        Message msg = dequeue(&priority);
        printf("Consumed: %d [Priority: %d]\n", msg.data, priority);
        usleep(150000);
    }
    
    return NULL;
}

int main() {
    init_priority_queue();

    pthread_t prod, cons;
    pthread_create(&prod, NULL, producer, NULL);
    pthread_create(&cons, NULL, consumer, NULL);

    pthread_join(prod, NULL);
    pthread_join(cons, NULL);

    return 0;
}
